package io.reactivex.rxjava3.rxohos.slice;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableSource;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.functions.Supplier;
import io.reactivex.rxjava3.openharmony.schedulers.OpenHarmonySchedulers;
import io.reactivex.rxjava3.openharmony.util.LogUtil;
import io.reactivex.rxjava3.observers.DisposableObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.eventhandler.EventRunner;

/**
 * Main ability slice class that will be displayed from MainAbility upon application launch
 */
public class MainAbilitySlice extends AbilitySlice {
    private static final int COLOR_WHITE = 0xFFFFFFFF;
    private static final int ID_TEXT = 100;
    private static final int ID_BUTTON = 200;
    private static final int ID_BUTTON2 = 300;
    private static final int ID_BUTTON3 = 400;
    private static final int ID_BUTTON4 = 500;
    private static String TAG = "MainAbilitySlice";
    private Button button;
    private Button button2;
    private Button button3;
    private Button button4;
    private Text text = null;
    private PositionLayout myLayout = new PositionLayout(this);
    private final CompositeDisposable disposables = new CompositeDisposable();

    private void setText(String inputtext) {
        text.setText(inputtext);
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        DirectionalLayout directionLayout = new DirectionalLayout(this);
        // Step 2 Set the layout size.
        directionLayout.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
        directionLayout.setHeight(ComponentContainer.LayoutConfig.MATCH_PARENT);
        // Step 3 Set the layout attributes and ID (set the ID as required).
        directionLayout.setOrientation(Component.VERTICAL);
        directionLayout.setPadding(32, 32, 32, 32);
        text = new Text(this);
        text.setText("No testcase being executed");
        text.setTextSize(50);
        text.setId(ID_TEXT);

        // Step 4.1 Add layout attributes for the control.
        DirectionalLayout.LayoutConfig layoutConfig =
                new DirectionalLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                        ComponentContainer.LayoutConfig.MATCH_CONTENT);
        text.setLayoutConfig(layoutConfig);

        // Step 4.2 Add Text to the layout.
        directionLayout.addComponent(text);

        // Add a button in the similar way.
        button = configureButton(ID_BUTTON, "Run on MainTask", layoutConfig, new Component.ClickedListener() {
            @Override
            // Add a listener for the click event to the control.
            public void onClick(Component Component) {
                rxOpenHarmonyTestCase1();
            }
        });
        directionLayout.addComponent(button);

        button2 = configureButton(ID_BUTTON2, "From New Thread Run observable on MainTask Thread",
                layoutConfig, new Component.ClickedListener() {
                    @Override
                    // Add a listener for the click event to the control.
                    public void onClick(Component Component) {
                        rxOpenHarmonyTestCase2();
                    }
                });
        directionLayout.addComponent(button2);

        button3 = configureButton(ID_BUTTON3, "Run on Background Thread", layoutConfig,
                new Component.ClickedListener() {
                    @Override
                    // Add a listener for the click event to the control.
                    public void onClick(Component Component) {
                        rxOpenHarmonyTestCase3();
                    }
                });
        directionLayout.addComponent(button3);

        button4 = configureButton(ID_BUTTON4, "Run on Background Thread2", layoutConfig,
                new Component.ClickedListener() {
                    @Override
                    // Add a listener for the click event to the control.
                    public void onClick(Component Component) {
                        rxOpenHarmonyTestCase4();
                    }
                });
        directionLayout.addComponent(button4);

        super.setUIContent(directionLayout);
    }

    private Button configureButton(
            int btnId, String btnText, DirectionalLayout.LayoutConfig layoutConfig,
            Component.ClickedListener clickedListener) {
        Button btn = new Button(this);
        btn.setLayoutConfig(layoutConfig);
        btn.setText(btnText);
        btn.setTextSize(50);
        btn.setId(btnId);
        ShapeElement background = new ShapeElement();
        background.setRgbColor(new RgbColor(0xFF51A8DD));
        btn.setBackground(background);
        btn.setPadding(10, 10, 10, 10);
        btn.setClickedListener(clickedListener);
        return btn;
    }

    /**
     * Method that will be invoked when the button is clicked for test case 1,
     * That is run on main thread.
     */
    public void rxOpenHarmonyTestCase1() {
        disposables.add(sampleObservable()
                // Run on a background thread
                .subscribeOn(Schedulers.io())
                // Be notified on the main thread
                .observeOn(OpenHarmonySchedulers.mainThread())
                .subscribeWith(new DisposableObserver<String>() {
                    @Override
                    public void onComplete() {
                        LogUtil.info(TAG, "onComplete()");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                        text.setText("Testcase1 finished");
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LogUtil.info(TAG, "onError()");
                    }

                    @Override
                    public void onNext(String string) {
                        LogUtil.info(TAG, "onNext(" + string + ")");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                        text.setText(string);
                    }
                }));
    }

    /**
     * Method that will be invoked when the button is clicked for test case 2,
     * That is from New Thread Run observable on MainTask Thread
     */
    public void rxOpenHarmonyTestCase2() {
        ThreadClass obj = new ThreadClass();
        obj.start();
    }

    /**
     * Method that will be invoked when the button is clicked for test case 3,
     * That is run on Background Thread in async mode
     */
    public void rxOpenHarmonyTestCase3() {
        EventRunner eventRunner = EventRunner.create("backgroundThread");
        disposables.add(sampleObservable()
                // Run on a background thread
                .subscribeOn(Schedulers.io())
                // Be notified on the main thread
                .observeOn(OpenHarmonySchedulers.from(eventRunner))
                .subscribeWith(new DisposableObserver<String>() {
                    @Override
                    public void onComplete() {
                        LogUtil.info(TAG, "onComplete()");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LogUtil.info(TAG, "onError()");
                    }

                    @Override
                    public void onNext(String string) {
                        LogUtil.info(TAG, "onNext(" + string + ")");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                    }
                }));
    }

    /**
     * Method that will be invoked when the button is clicked for test case 4,
     * That is run on Background Thread in sync mode
     */
    public void rxOpenHarmonyTestCase4() {
        EventRunner eventRunner = EventRunner.create("backgroundThread");
        disposables.add(sampleObservable()
                // Run on a background thread
                .subscribeOn(Schedulers.io())
                // Be notified on the main thread
                .observeOn(OpenHarmonySchedulers.from(eventRunner, true))
                .subscribeWith(new DisposableObserver<String>() {
                    @Override
                    public void onComplete() {
                        LogUtil.info(TAG, "onComplete()");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        LogUtil.info(TAG, "onError()");
                    }

                    @Override
                    public void onNext(String string) {
                        LogUtil.info(TAG, "onNext(" + string + ")");
                        LogUtil.info(TAG, Thread.currentThread().getName());
                    }
                }));
    }

    /**
     * A thread class for running the observable in new thread but on main thread
     */
    public class ThreadClass extends Thread {
        @Override
        public void run() {
            LogUtil.info(TAG, Thread.currentThread().getName());
            disposables.add(sampleObservable()
                    // Run on a background thread
                    .subscribeOn(Schedulers.io())
                    // Be notified on the main thread
                    .observeOn(OpenHarmonySchedulers.mainThread())
                    .subscribeWith(new DisposableObserver<String>() {
                        @Override
                        public void onComplete() {
                            LogUtil.info(TAG, "onComplete()");
                            LogUtil.info(TAG, Thread.currentThread().getName());
                            text.setText("Testcase2 finished");
                        }

                        @Override
                        public void onError(Throwable throwable) {
                            LogUtil.info(TAG, "onError()");
                        }

                        @Override
                        public void onNext(String string) {
                            LogUtil.info(TAG, "onNext(" + string + ")");
                            LogUtil.info(TAG, Thread.currentThread().getName());
                            text.setText(string);
                        }
                    }));
        }
    }

    static Observable<String> sampleObservable() {
        return Observable.defer(new Supplier<ObservableSource<? extends String>>() {
            @Override
            public ObservableSource<? extends String> get() throws Throwable {
                // Do some long running operation
                Thread.sleep(5000);
                return Observable.just("one", "two", "three", "four", "five");
            }
        });
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}
